﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SSharp.Core.DataTypes;

namespace SSharp.Core.Evaluator {
	/// <summary>
	/// The frame is a set of symbols and their values.
	/// </summary>
	public interface IFrame : IEnumerable<KeyValuePair<Symbol, Box>> {
		/// <summary>
		/// Gets or sets a value in the frame.
		/// Set to null to signify that the frame does not have that key.
		/// Set to a box containing null to signify a null value in that variable.
		/// Set to a box containing the variable's value in all other cases.
		/// 
		/// This method should never throw; if the variable doesn't exist, return null.
		/// </summary>
		Box this[Symbol key] { get; set; }

		/// <summary>
		/// Convenience access for this[Symbol]
		/// </summary>
		Box this[string key] { get; set; }
	}

	/// <summary>
	/// Implements the IFrame interface
	/// </summary>
	public class Frame : IFrame {
		private Dictionary<Symbol, Box> dict;

		/// <summary>
		/// Initializes an empty frame
		/// </summary>
		public Frame() {
			dict = new Dictionary<Symbol, Box>();
		}

		/// <summary>
		/// Initializes a frame with the given definitions
		/// </summary>
		public Frame(Dictionary<Symbol, object> definitions)
			: this() {

			foreach (KeyValuePair<Symbol, object> entry in definitions) {
				this[entry.Key] = new Box(entry.Value);
			}
		}

		/// <summary>
		/// Initializes a frame with the given definitions
		/// </summary>
		public Frame(Dictionary<string, object> definitions)
			: this() {

			foreach (KeyValuePair<string, object> entry in definitions) {
				this[entry.Key] = new Box(entry.Value);
			}
		}

		public Box this[Symbol key] {
			get {
				// delegate to the dictionary, but use TryGetValue to not throw when the key is not found.
				Box result;
				dict.TryGetValue(key, out result);
				return result;
			}
			set { dict[key] = value; }
		}

		public Box this[string key] {
			get { return this[new Symbol(key)]; }
			set { this[new Symbol(key)] = value; }
		}

		public IEnumerator<KeyValuePair<Symbol, Box>> GetEnumerator() {
			return dict.GetEnumerator();
		}

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
			return dict.GetEnumerator();
		}
	}
}
